/**********************************************************************************
 *  jcw - this is a environment for solving japan crosswords by users on computer *
 *  Copyright (C) 2008 by pluton <plutonpluton@mail.ru>                           *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or modify          *
 *  it under the terms of the GNU General Public License as published by          *
 *  the Free Software Foundation; either version 2 of the License, or             *
 *  (at your option) any later version.                                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,               *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
 *  GNU General Public License for more details.                                  *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License along       *
 *  with this program; if not, write to the Free Software Foundation, Inc.,       *
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                   *
 *********************************************************************************/

#include "mainwnd.h"

MainWnd::MainWnd(QWidget* parent, Qt::WindowFlags f)
	: QMainWindow(parent, f)
{
	crossword = NULL;
	
	/*		настройки глав окна 	*/
	windowName = new QString("jcw");
	this->setWindowTitle(*windowName);
	this->setGeometry(150, 150, 800, 600);
	
	/*		создаём меню и тулбар		*/
	menuBar = new QMenuBar(this);
	toolBar = new QToolBar(tr("Standart"), this);
	
	menu = new QMenu(tr("&File"), menuBar);
	menuBar->addMenu(menu);
	
	newCWAction = new QAction(tr("&New crossword..."), menu); //create crossword
	newCWAction->setShortcut(Qt::CTRL + Qt::Key_N);
	newCWAction->setIcon(QIcon(":/pics/filenew.png"));
	connect(newCWAction, SIGNAL(triggered()), SLOT(newCrossword()));
	menu->addAction(newCWAction);
	toolBar->addAction(newCWAction);
	
	openCWAction = new QAction(tr("&Open crossword..."), menu); //open crossword
	openCWAction->setShortcut(Qt::CTRL + Qt::Key_O);
	openCWAction->setIcon(QIcon(":/pics/fileopen.png"));
	connect(openCWAction, SIGNAL(triggered()), SLOT(openCrossword()));
	menu->addAction(openCWAction);
	toolBar->addAction(openCWAction);
	
	saveCWAction = new QAction(tr("&Save crossword..."), menu); //save crossword
	saveCWAction->setShortcut(Qt::CTRL + Qt::Key_S);
	saveCWAction->setIcon(QIcon(":/pics/filesave.png"));
	saveCWAction->setEnabled(false);
	connect(saveCWAction, SIGNAL(triggered()), SLOT(saveCrossword()));
	menu->addAction(saveCWAction);
	toolBar->addAction(saveCWAction);
	
	undoAction = new QAction(tr("&Undo..."), menu); //undo
	undoAction->setShortcut(Qt::CTRL + Qt::Key_Z);
	undoAction->setEnabled(false);
	toolBar->addAction(undoAction);

	redoAction = new QAction(tr("&Redo..."), menu); //redo
	redoAction->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Z);
	redoAction->setEnabled(false);
	toolBar->addAction(redoAction);

	showInfoAction = new QAction(tr("Show &info..."), menu);		// показать инфу о кроссворде
	showInfoAction->setShortcut(Qt::CTRL + Qt::Key_I);
	showInfoAction->setEnabled(false);
	menu->addAction(showInfoAction);
	toolBar->addAction(showInfoAction);

	clearFieldAction = new QAction(tr("&Clear field"), menu);		// очистка поля
	clearFieldAction->setShortcut(Qt::CTRL + Qt::Key_C);
	clearFieldAction->setEnabled(false);
	menu->addAction(clearFieldAction);
	toolBar->addAction(clearFieldAction);

	menu->addSeparator();
	toolBar->addSeparator();

	quitAction = new QAction(tr("&Quit"), menu);					// выход
	quitAction->setShortcut(Qt::ALT + Qt::Key_F4);
	quitAction->setIcon(QIcon(":/pics/quit.png"));
	connect(quitAction, SIGNAL(triggered()), SLOT(close()));
	menu->addAction(quitAction);
	toolBar->addAction(quitAction);

	menu = new QMenu(tr("&Solving"), menuBar);
	menuBar->addMenu(menu);
	menu->addAction(undoAction);
	menu->addAction(redoAction);
	tryToSolveAction = menu->addAction(tr("Try &to solve"), this, SLOT(solveCrossword()), Qt::CTRL + Qt::Key_R);
	tryToSolveAction->setEnabled(false);

	menu = new QMenu(tr("&About"), menuBar);
	menuBar->addMenu(menu);
	aboutAction = menu->addAction(tr("About &Qt..."), qApp, SLOT(aboutQt()), Qt::SHIFT + Qt::Key_F1);

	this->setMenuBar(menuBar);
	this->addToolBar(Qt::TopToolBarArea, toolBar);

	/*		добавляем статусбар		*/
	statusBar = new QStatusBar(this);
	solveProgress = new QProgressBar(statusBar);
	statusBar->addWidget(solveProgress);
	checkResultLabel = new QLabel("---", statusBar);
	statusBar->addWidget(checkResultLabel);
	solvingTimeLabel = new QLabel(statusBar);
	statusBar->addWidget(solvingTimeLabel);
	this->setStatusBar(statusBar);
	
	/*		добавляем виджеты		*/
	body = new QWidget(this);
	bodyLayout = new QHBoxLayout;
	scrollArea = new QScrollArea(this);
	bodyLayout->addWidget(scrollArea);
	rightPanel = new QWidget(this);
	rightPanel->setMinimumWidth(50);
	paletteLayout = new QVBoxLayout;
	brushPalette = new ColorSelector(Palette::Brush);
	layerPalette = new ColorSelector(Palette::Layer);
	connect(layerPalette, SIGNAL(currItemChanged(quint16)), brushPalette, SLOT(layerSet(quint16)));
	paletteLayout->addWidget(brushPalette);
	paletteLayout->addWidget(layerPalette);
	paletteLayout->addStretch();
	rightPanel->setLayout(paletteLayout);
	bodyLayout->addWidget(rightPanel);
	body->setLayout(bodyLayout);
	this->setCentralWidget(body);
	scrollArea->show();
	rightPanel->setVisible(false);

	/*Adding timer*/
	solvingTimer = new QTimer(crossword);
	solvingTimer->setInterval(1000);
	connect(solvingTimer, SIGNAL(timeout()), SLOT(solvingTimerTimeout()));

	fieldChecker.start();
	connect(&fieldChecker, SIGNAL(resultTextChanged(QString)), checkResultLabel, SLOT(setText(QString)));
	connect(&fieldChecker, SIGNAL(solved()), SLOT(solved()));
	connect(&fieldChecker, SIGNAL(progressChanged(int)), solveProgress, SLOT(setValue(int)));
}

MainWnd::~MainWnd()
{
	fieldChecker.exit();
}

void MainWnd::openCrossword(QFile & file)
{
	if (!file.open(QIODevice::ReadOnly))	// если ошибка открытия файла
	{
		QMessageBox::critical(this, tr("Error"), tr("Can't open file"));
		return;
	}

	QDomDocument domDoc;
	QString errorMsg;
	int errorLine;
	int errorCol;
	if (!domDoc.setContent(&file, &errorMsg, &errorLine, &errorCol))	// если ошибка парсинга файла
	{
		/*QMessageBox::critical(this, tr("Error"), tr("Invalid file (") + errorMsg +
				tr(")\nError line: ") + QString::number(errorLine) + tr("\nError column: ") +
				QString::number(errorCol));*/
		QMessageBox::critical(this, tr("Error"), QString(tr(
				"Invalid file (%1)\nError line: %2\nError column: %3")).arg(errorMsg).arg(
				QString::number(errorLine)).arg(QString::number(errorCol)));
		return;
	}

	QDomElement domElement = domDoc.documentElement();
	if ((!domElement.isNull()) && domElement.isElement())
	{
		domElement = domElement.toElement();
		if ((!domElement.isNull()) && (domElement.tagName() == "crossword"))
		{
			QString type = domElement.attribute("type");

			if (crossword != NULL)
				doDeleteCrossword();

			if (type == "classic")
			{
				crossword = new ClassicCW(&solvingTime);
				((ClassicCW*) crossword)->init(domDoc.documentElement());
				fieldChecker.setCrossword(crossword, CWType::Classic, CWType::SolvingCrossword);
				undoAction->setEnabled(true);
				redoAction->setEnabled(true);
				tryToSolveAction->setEnabled(true);
			}
			else if (type == "color")
			{
				rightPanel->setVisible(true);
				crossword = new ColorCW(&solvingTime);
				((ColorCW*) crossword)->init(domDoc.documentElement());
				brushPalette->setColorMap(((ColorCW*) crossword)->getColorMap(), ((ColorCW*) crossword)->getColorMapCnt());
				layerPalette->setColorMap(((ColorCW*) crossword)->getColorMap(), ((ColorCW*) crossword)->getColorMapCnt());
				connect(brushPalette, SIGNAL(currItemChanged(quint16)), crossword, SLOT(setPenColor(quint16)));
				connect(layerPalette, SIGNAL(currItemChanged(quint16)), crossword, SLOT(setCurrentLayer(quint16)));
				fieldChecker.setCrossword(crossword, CWType::Color, CWType::SolvingCrossword);
			}
			else
				return;

			if (crossword->isNeedDelete())
			{
				QMessageBox::critical(this, tr("Error"), tr("Invalid values in file"));
				doDeleteCrossword();
			}
			else
			{
				crossword->setGeometry(3, 3, 695, 495);
				scrollArea->setWidget(crossword);
				showInfoAction->setEnabled(true);
				saveCWAction->setEnabled(true);
				clearFieldAction->setEnabled(true);
				if (!crossword->getName().isEmpty())
					setWindowTitle(QString("%1 - %2").arg(*windowName).arg(crossword->getName()));
				connect(showInfoAction, SIGNAL(triggered()), crossword, SLOT(showInfo()));
				connect(clearFieldAction, SIGNAL(triggered()), crossword, SLOT(clearField()));
				connect(undoAction, SIGNAL(triggered()), crossword, SLOT(undo()));
				connect(redoAction, SIGNAL(triggered()), crossword, SLOT(redo()));
				//solveProgress->setValue(0);
				crossword->updateProgress();
				solvingTimer->start();
			}
		}
	}

	file.close();
}

void MainWnd::openCrossword()
{
	QString fileName = QFileDialog::getOpenFileName(this, tr("Open crossword"), QLatin1String(CRWDDIR),
			tr("Crosswords (*.jcw);;All files(*)"));
	if (fileName == NULL)					// если ничё не выбрано, то выход
		return;
	
	QFile file(fileName);
	openCrossword(file);
}

void MainWnd::solved()
{
	solvingTimer->stop();
	crossword->updatePixmap();
	QMessageBox::information(this, tr("Crossword solved"), QString(tr(
	 "You win!\nCongratulations and blah-blah-blah\nElapsed time to solving: %1\nCorrections count: %2").
	 arg(solvingTime.toString("H:mm:ss")).arg(crossword->getNumCorrections())));
	crossword->solved();
	clearFieldAction->setEnabled(false);
	saveCWAction->setEnabled(false);
}

void MainWnd::solvingTimerTimeout()
{
	solvingTime = solvingTime.addSecs(1);
	solvingTimeLabel->setText(QString(tr("Elapsed time: %1")).arg(solvingTime.toString("H:mm:ss")));
}

void MainWnd::saveCrossword()
{
	crossword->save();
}

void MainWnd::newCrossword()
{
	NewCWDialog* newDialog = new NewCWDialog(this);
	if (newDialog->exec() != QDialog::Accepted)
		return;
	quint16 cwWidth = newDialog->getCWWidth();
	quint16 cwHeight = newDialog->getCWHeight();
	quint16 tHeight = newDialog->getTHeight();
	quint16 lWidth = newDialog->getLWidth();

	if (crossword != NULL)
		doDeleteCrossword();
	if (newDialog->getMode() == CWType::PaintCrossword)
		crossword = new ClassicCW(cwWidth, cwHeight, &solvingTime);
	else if (newDialog->getMode() == CWType::FillUpHeaders)
		crossword = new ClassicCW(cwWidth, cwHeight, tHeight, lWidth, &solvingTime);

	crossword->setGeometry(3, 3, 695, 495);
	scrollArea->setWidget(crossword);
	showInfoAction->setEnabled(true);
	clearFieldAction->setEnabled(true);
	saveCWAction->setEnabled(true);

	if (!crossword->getName().isEmpty())
	setWindowTitle(QString("%1 - %2").arg(*windowName).arg(crossword->getName()));
	fieldChecker.setCrossword(crossword, newDialog->getType(), newDialog->getMode());
	connect(showInfoAction, SIGNAL(triggered()), crossword, SLOT(showInfo()));
	connect(clearFieldAction, SIGNAL(triggered()), crossword, SLOT(clearField()));
	connect(undoAction, SIGNAL(triggered()), crossword, SLOT(undo()));
	connect(redoAction, SIGNAL(triggered()), crossword, SLOT(redo()));
	//solveProgress->setValue(0);
	crossword->updateProgress();
/*	solvingTimer = new QTimer(crossword);
	solvingTimer->setInterval(1000);
	connect(solvingTimer, SIGNAL(timeout()), SLOT(solvingTimerTimeout()));
	solvingTimer->start();*/

}

void MainWnd::solveCrossword()
{
	if (!crossword->solve())
		QMessageBox::critical(this, tr("Error"), QString(tr("Error occured while solving crossword")));
}

void MainWnd::doDeleteCrossword()
{
	rightPanel->setVisible(false);
	showInfoAction->setEnabled(false);
	clearFieldAction->setEnabled(false);
	saveCWAction->setEnabled(false);
	undoAction->setEnabled(false);
	redoAction->setEnabled(false);
	tryToSolveAction->setEnabled(false);
	disconnect(showInfoAction, SIGNAL(triggered()), crossword, SLOT(showInfo()));
	disconnect(clearFieldAction, SIGNAL(triggered()), crossword, SLOT(clearField()));
	disconnect(undoAction, SIGNAL(triggered()), crossword, SLOT(undo()));
	disconnect(redoAction, SIGNAL(triggered()), crossword, SLOT(redo()));
	if (((RectCrossword*) crossword)->getType() == CWType::Color)
	{
		disconnect(brushPalette, SIGNAL(currItemChanged(quint16)), crossword, SLOT(setPenColor(quint16)));
		disconnect(layerPalette, SIGNAL(currItemChanged(quint16)), crossword, SLOT(setCurrentLayer(quint16)));
	}
	solvingTimer->stop();
	delete crossword;
	crossword = NULL;
}
